OSS + Ant Design Upload 网页直传

文档

https://help.aliyun.com/document_detail/32069.html?spm=a2c4g.11186623.6.1333.2b4349475kQkEE

具体实现

ali-oss

1
yarn add ali-oss

获取直传token

请求服务端接口获取直传token:

1
2
3
4
5
6
7
const ossConfig = {
accessKeyId: res.access_key_id,
accessKeySecret: res.access_key_secret,
stsToken: res.security_token,
region: res.region,
bucket: res.bucket,
}

为避免频繁请求token,将token存在localstorage中,比较token中的过期时间,判断过期后才重新获取。

spark-md5获取文件的md5值

1
yarn add spark-md5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const readAsArrayBuffer = useCallback((data) => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsArrayBuffer(data)
reader.onload = (evt) => {
const body = evt.target?.result
resolve(body)
}
reader.onerror = () => {
reject()
}
})
}, [])

const computeMd5 = useCallback(async (file) => {
const Md5ChunkSize = 2097152
let currentChunk = 0
const chunks = Math.ceil(file.size / Md5ChunkSize)
const spark = new SparkMD5.ArrayBuffer()

while (currentChunk < chunks) {
const start = currentChunk * Md5ChunkSize
const end = start + Md5ChunkSize >= file.size ? file.size : start + Md5ChunkSize

const buffer = await readAsArrayBuffer(file.slice(start, end))
spark.append(buffer)
currentChunk++
}

return spark.end()
}, [readAsArrayBuffer])

结合Ant Design Upload

OSSUpload组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
function OSSUpload(props) {
const {children, ...restProps} = props

const auth = useRef(null)
const authLoading = useRef(false)

const checkTokenExpired = useCallback(() => {
if (!auth.current) {
auth.current = getLocalToken()
}
const expiredTime = auth.current?.credentials?.expiration || 0
return moment().isAfter(expiredTime)
}, [])

const getAuth = useCallback(() => new Promise(async (resolve, reject) => {
if (checkTokenExpired()) {
if (authLoading.current) {
return
}
auth.current = null
authLoading.current = true
removeLocalToken()
try {
const res = await API.uploadAuth()
if (!checkTokenExpired()) {
resolve()
return
}
if (res?.meta?.code === 200) {
auth.current = res.data
setLocalToken(auth.current)
resolve()
} else {
reject()
}
} catch (e) {
reject()
} finally {
authLoading.current = false
}
} else {
resolve(auth.current)
}
}), [checkTokenExpired])

const getFilename = useCallback((file, hash) => {
const idx = file.name.lastIndexOf('.')
let ext = ''
if (idx !== -1) {
ext = file.name.substr(idx)
}
return `${auth.current.dir}${hash}${ext}`
}, [])

const beforeUpload = useCallback(async (file, fileList) => {
try {
const {beforeUpload} = props
if (beforeUpload) {
const res = await beforeUpload(file, fileList)
if (res === false) {
return Upload.LIST_IGNORE
}
}
await getAuth()
} catch (e) {
return Upload.LIST_IGNORE
}
}, [getAuth, props])

const upload = useCallback((option) => {
if (!auth.current) {
return
}
const {file, onProgress, onSuccess, onError} = option

computeMd5(file)
.then((hash) => {
const filename = getFilename(file, hash)

const AliClient = new OSS(ossConfig)

return new Promise((resolve, reject) => {
AliClient
.multipartUpload(
filename,
file,
{
progress: async (percent) => {
onProgress({percent: percent * 100})
},
}
)
.then((result) => {
const ossPath = result.res.requestUrls[0].split('?')[0]
const url = ossPath.replace(/^http:\/\//i, 'https://')
const data = {
status: result?.res?.status,
name: result?.name,
url: url,
}
onSuccess(data)
resolve(result)
})
.catch((error) => {
onError(error)
reject(error)
})
})
})
.catch((e) => {
console.log(e)
onError(e)
})
}, [computeMd5, getFilename])

const customRequest = useCallback((option) => upload(option), [upload])

const uploadProps = {
...restProps,
beforeUpload: beforeUpload,
customRequest: props.customRequest ? props.customRequest : customRequest,
}

return (
<Upload {...uploadProps}>
{children}
</Upload>
)
}

使用

1
2
3
<OSSUpload {...uploadProps}>
<div>Change Avatar</div>
</OSSUpload>

图片处理

图片缩放处理

https://help.aliyun.com/document_detail/44688.html?spm=a2c4g.11186623.6.743.2ad549c061kTcJ